#include "aki/jsbind.h"
#include "xcomponent_render_manager.h"

XcomponentRendersManager XcomponentRendersManager::instance_;
std::unordered_map<std::string, std::shared_ptr<I420Render>> XcomponentRendersManager::renders;
std::unordered_map<std::string, OH_NativeXComponent*> XcomponentRendersManager::nativeXcomponentMap_;

XcomponentRendersManager &XcomponentRendersManager::GetInstance()
{
    return instance_;
}

std::shared_ptr<I420Render> XcomponentRendersManager::GetRender(std::string id)
{
    auto it = XcomponentRendersManager::renders.find(id);
    if (it == XcomponentRendersManager::renders.end()) {
        return nullptr;
    }
    return XcomponentRendersManager::renders[id];
}

std::shared_ptr<I420Render> XcomponentRendersManager::AddRender(std::string id)
{
    auto it = renders.find(id);
    if (it == renders.end()) {
        renders[id] = std::make_shared<I420Render>();
    }
    return renders[id];
}

int32_t XcomponentRendersManager::RegisterCallback(OH_NativeXComponent *nativeXComponent)
{
    renderCallback_.OnSurfaceCreated = Callbacks::OnSurfaceCreatedCB;
    renderCallback_.OnSurfaceChanged = Callbacks::OnSurfaceChangedCB;
    renderCallback_.OnSurfaceDestroyed = Callbacks::OnSurfaceDestroyedCB;
    renderCallback_.DispatchTouchEvent = Callbacks::OnDispatchTouchEventCB;

    return OH_NativeXComponent_RegisterCallback(nativeXComponent, &renderCallback_);
}

int32_t XcomponentRendersManager::RegisterCallback(std::string id)
{
    auto it = XcomponentRendersManager::nativeXcomponentMap_.find(id);
    if (it == XcomponentRendersManager::nativeXcomponentMap_.end()) {
        AKI_LOG(ERROR) << "nativeXcomponentMap_ " << id << " is empty";
        return -1;
    }
    OH_NativeXComponent *nativeXComponent = XcomponentRendersManager::nativeXcomponentMap_[id];
    return RegisterCallback(nativeXComponent);
}

void XcomponentRendersManager::Callbacks::OnDispatchTouchEventCB(OH_NativeXComponent *component, void *window)
{
    AKI_DLOG(INFO) << "OnDispatchTouchEventCB";
}

void XcomponentRendersManager::Callbacks::OnSurfaceChangedCB(OH_NativeXComponent *component, void *window)
{
    AKI_DLOG(INFO) << "OnSurfaceChangedCB";
}

void XcomponentRendersManager::Callbacks::OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window)
{
    char id[OH_XCOMPONENT_ID_LEN_MAX + 1] = {0};
    uint64_t len = OH_XCOMPONENT_ID_LEN_MAX;
    int32_t ret = OH_NativeXComponent_GetXComponentId(component, id, &len);
    if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
        AKI_LOG(ERROR) << "OH_NativeXComponent_GetXComponentId failed : len = " << len << " ret = " << ret;
        return;
    }
    std::shared_ptr<I420Render> render = XcomponentRendersManager::GetInstance().AddRender(id);
    if (render == nullptr) {
        AKI_LOG(ERROR) << "GetRender failed";
        return;
    }
    
    AKI_DLOG(INFO) << "OnSurfaceCreatedCB" << id;
    uint64_t width, height;
    ret = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height);
    if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
        AKI_LOG(ERROR) << "OH_NativeXComponent_GetXComponentSize failed";
        return;
    }
    ret = render->Init(width, height, static_cast<OHNativeWindow *>(window));
    if (ret != 0) {
        AKI_LOG(ERROR) << "render->Init failed";
        return;
    }
}

void XcomponentRendersManager::Callbacks::OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window)
{
    AKI_DLOG(INFO) << "OnSurfaceDestroyedCB";
}

int32_t XcomponentRendersManager::SetNativeXcomponent(std::string id, OH_NativeXComponent* nativeXComponent)
{
    auto it = XcomponentRendersManager::nativeXcomponentMap_.find(id);
    if (it == XcomponentRendersManager::nativeXcomponentMap_.end()) {
        XcomponentRendersManager::nativeXcomponentMap_[id] = nativeXComponent;
    }
    return 0;
}